package com.chenchen.code.guava.concurrent;

import com.google.common.collect.Lists;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description: 生产者消费者
 * @author chenchen
 * @date 2019/5/17 13:31
 */
public class MonitorExample {

    public static void main(String[] args) {
        final ExecutorService executorPut = Executors.newFixedThreadPool(3);
        final ExecutorService executorTake = Executors.newFixedThreadPool(3);
        final AtomicInteger counter = new AtomicInteger(0);
        Synchronized container = new MonitorExample.Synchronized();
        while (true) {
            executorPut.submit(() -> {
                int data = counter.getAndIncrement();
                container.put(data);
                try {
                    TimeUnit.MILLISECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            executorTake.submit(() -> {
                container.take();
                try {
                    TimeUnit.MILLISECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    static class Synchronized {
        private final LinkedList<Integer> queue = Lists.newLinkedList();
        private final int MAX = 10;

        public void put(int value) {
            synchronized(queue) {
                while(queue.size() >= MAX) {
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + " put " + value);
                queue.addLast(value);
                queue.notifyAll();
            }
        }

        public int take() {
            synchronized(queue) {
                while(queue.isEmpty()) {
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                Integer value = queue.removeFirst();
                queue.notifyAll();
                System.out.println(Thread.currentThread().getName() + " take " + value);
                return value;
            }
        }
    }


    static class LockCondition
    {
        private final ReentrantLock lock = new ReentrantLock();

        private final Condition FULL_CONDITION = lock.newCondition();

        private final Condition EMPTY_CONDITION = lock.newCondition();

        private final LinkedList<Integer> queue = new LinkedList<>();

        private final int MAX = 10;

        public void offer(int value)
        {
            try
            {
                lock.lock();
                while (queue.size() >= MAX)
                {
                    FULL_CONDITION.await();
                }

                queue.addLast(value);
                EMPTY_CONDITION.signalAll();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            } finally
            {
                lock.unlock();
            }
        }

        public int take()
        {

            Integer value = null;
            try
            {
                lock.lock();
                while (queue.isEmpty())
                {
                    EMPTY_CONDITION.await();
                }

                value = queue.removeFirst();
                FULL_CONDITION.signalAll();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            } finally
            {
                lock.unlock();
            }

            return value;
        }
    }

}
